import json
import xml.etree.ElementTree as ET
import pandas as pd
from collections import defaultdict, deque
import requests


# 命名空间定义
NS = {
    'bpmn': 'http://www.omg.org/spec/BPMN/20100524/MODEL'
}
#跳过网关提取BPMN
def parse_bpmn_skip_unnamed_gateways(file_path):
    tree = ET.parse(file_path)
    root = tree.getroot()
    process = root.find('bpmn:process', NS)

    id_name_map = {}
    outgoing_map = defaultdict(list)

    # Step 1: 获取所有非 sequenceFlow 节点（用于名称映射）
    for elem in process:
        tag = elem.tag.split('}')[-1]
        if tag != 'sequenceFlow':
            node_id = elem.attrib['id']
            name = elem.attrib.get('name', '').strip() or "Unnamed"
            id_name_map[node_id] = name

    # Step 2: 获取所有 sequenceFlow（用于图结构）
    for seq in process.findall('bpmn:sequenceFlow', NS):
        source = seq.attrib['sourceRef']
        target = seq.attrib['targetRef']
        outgoing_map[source].append(target)

    # Step 3: 获取 startEvent 的 ID
    start_node_id = None
    for elem in process.findall('bpmn:startEvent', NS):
        start_node_id = elem.attrib.get('id')
        break
    if not start_node_id:
        raise ValueError("未找到 startEvent 节点")

    # Step 4: 递归展开分支，跳过 Unnamed 网关
    def resolve_next_nodes(node_id):
        """从当前节点出发，返回所有实际可达的非Unnamed节点ID列表"""
        result = []
        targets = outgoing_map.get(node_id, [])
        for tgt in targets:
            name = id_name_map.get(tgt, 'Unnamed')
            if name != 'Unnamed':
                result.append(tgt)
            else:
                # 当前是 unnamed 控制节点，递归继续展开
                result.extend(resolve_next_nodes(tgt))
        return result

    # Step 5: BFS 遍历路径，记录路径（跳过中间 Unnamed）
    path_records = []
    queue = deque()
    queue.append(start_node_id)

    seq_id = 1
    visited = set()  # 防止死循环

    while queue:
        current_id = queue.popleft()
        current_name = id_name_map.get(current_id, 'Unnamed')

        for next_id in resolve_next_nodes(current_id):
            next_name = id_name_map.get(next_id, 'Unnamed')

            path_records.append({
                'id': seq_id,
                'now_state': current_name,
                'next_state': next_name
            })
            seq_id += 1

            # 避免重复节点造成死循环（可选）
            if next_id not in visited:
                visited.add(next_id)
                queue.append(next_id)

    # 构建 DataFrame
    sequence_df = pd.DataFrame(path_records, columns=['id', 'now_state', 'next_state'])
    sequence_json = sequence_df.to_dict(orient='records')
    # 转化成大模型可阅读json文本
    #sequence_json = json.dumps(sequence_json, ensure_ascii=False, indent=2)
    return  sequence_df,sequence_json



if __name__ == "__main__":
    webhook_url = "http://39.107.64.125:5678/webhook/6f821ff6-84e1-4b6c-a240-dc145410ab60"
    bpmn_file = r'C:\Users\renming\Desktop\研究生\农业部项目\审稿流程定制\外审.bpmn'  # 替换为你的 BPMN 文件路径
    sequence_df,sequence_json = parse_bpmn_skip_unnamed_gateways(bpmn_file)
    print("\n🔸 跳过 Unnamed 控制节点的有序流程:")
    print(sequence_df)
    print(sequence_json)
    #调用n8n
    # 构造你要发送的数据（JSON 格式）
    payload = {
        "sessionId": 1235646545968898,
        "sequence_json":sequence_json,
        # "chatInput":"现在只有以下几个task：1.选择初审稿件，2.获取初审意见，3.发送初审通过邮件，4.推荐责编，5.选择外审稿件，6.汇总评审意见，7.发送初审拒稿邮件，8.发送初审修改后再审邮件，"
        #             "9.选择外审专家，10.接收评审意见，11.汇总评审意见，12.发送外审邮件。只用上述8个任务中的部分或全部，根据我下面的描述，使用POWL语言进行流程建模，这是我的描述： 责编首先会选择稿件，"
        #             "根据稿件类型执行不同工作，若稿件尚未进行外审，则为该稿件推荐外审专家，等待外审专家同意并返回审稿意见，若稿件已经推荐完外审专家且同行审稿人意见已返回，则汇总评审意见，"
        #             "汇总完评审意见后给作者发送邮件，当次评审结束"
        "chatInput":"外审专家超过7天没有接受邀请则视作失败，15天没有返回审稿意见同样视作失败"
    }
    print(payload)
    # 发送 POST 请求
    response = requests.post(webhook_url, json=payload)

    # 打印返回结果
    print("Response:", response.text)



















